package cn.kivensoft.util;

import java.lang.reflect.Array;

/** 基本类型动态数组类
 * @author kiven lee
 * @version 1.0
 */
abstract public class FastArray<T> {
	protected static final int B0 = 5; // Initial capacity in bits.
	protected static final int C0 = 1 << B0; // Initial capacity (32)
	protected static final int B1 = 10; // Low array maximum capacity in bits.
	protected static final int C1 = 1 << B1; // Low array maximum capacity (1024).
	protected static final int M1 = C1 - 1; // Mask.

	// Resizes up to 1024 maximum (32, 64, 128, 256, 512, 1024).
	protected T _low;
	// For larger capacity use multi-dimensional array.
	protected T[] _high;

	// Holds the current length.
	protected int _length;

	// Holds current capacity.
	protected int _capacity;

	abstract protected T newArray(int capacity);
	abstract protected T[] newHighArray(int size);

	/** 在指定位置插入数组
	 * @param index 插入的起始位置
	 * @param src 源数组
	 * @param srcBegin 源起始位置
	 * @param srcEnd 源结束位置
	 */
	abstract public void insert(int index, T src, int srcBegin, int srcEnd);

	/** 删除指定区间的元素, 后面的元素会前移, 长度会自动减少
	 * @param begin 起始位置
	 * @param end 结束位置
	 */
	abstract public void delete(int begin, int end);

	final protected void increaseCapacity() {
		if (_capacity < C1) { // For small capacity, resize.
			_capacity <<= 1;
			T tmp = newArray(_capacity);
			//noinspection SuspiciousSystemArraycopy
			System.arraycopy(_low, 0, tmp, 0, _length);
			_low = tmp;
			_high[0] = tmp;
		} else { // Add a new low block of 1024 elements.
			int highIndex = _capacity >> B1;
			if (highIndex >= _high.length) { // Resizes _high.
				T[] tmp = newHighArray(_high.length * 2);
				System.arraycopy(_high, 0, tmp, 0, _high.length);
				_high = tmp;
			}
			_high[highIndex] = newArray(C1);
			_capacity += C1;
		}
	}

	// 扩充缓冲区大小至指定的长度
	final protected void increaseCapacity(int capacity) {
		while (capacity > _capacity) increaseCapacity();
	}

	public FastArray() {
		_capacity = C0;
		_low = newArray(C0);
		_high = newHighArray(1);
		_high[0] = _low;
	}

	/**
	 * @param capacity 数组容量
	 */
	public FastArray(int capacity) {
		int cap;
		if (capacity > C1) {
			cap = C1;
			while (cap < capacity) cap += C1;
			int high_len = cap >> B1;
			_low = newArray(C1);
			_high = newHighArray(high_len);
			for (int i = 1; i < high_len; ++i)
				_high[i] = newArray(C1);
		} else {
			cap = C0;
			while (cap < capacity) cap <<= 1;
			_low = newArray(cap);
			_high = newHighArray(1);
		}
		_high[0] = _low;
		_capacity = cap;
	}

	/** 返回数组的当前有效长度 */
	public int length() {
		return _length;
	}

	/** 返回数组的当前容量大小 */
	public int capacity() {
		return _capacity;
	}

	/** 返回数组是否为空的标志 */
	public boolean isEmpty() {
		return _length == 0;
	}

	/** 设置数组新的长度, 不能为负数, 可比当前有效长度长或者短
	 * @param newLength 新的长度
	 */
	public void setLength(int newLength) {
		if (newLength > _capacity) increaseCapacity(newLength);
		_length = newLength;
	}

	/** 清空数组, 设置有效长度为0 */
	public void clear() {
		_length = 0;
	}

	public interface onForEach<T> {
		int call(T array, int offset, int length, int result);
	}

	/** 分片循环所有元素
	 * @param act 回调处理接口
	 */
	final public void forEach(onForEach<T> act) {
		forEach(0, _length, 0, act);
	}

	/** 分片循环指定区间的元素
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @param act 回调处理接口
	 */
	final public void forEach(int begin, int end, onForEach<T> act) {
		forEach(begin, end, 0, act);
	}

	/** 分片循环指定区间的元素
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @param init 回调接口的初始值
	 * @param act 回调处理接口
	 */
	final public void forEach(int begin, int end, int init, onForEach<T> act) {
		while (begin < end) {
			T va = _high[begin >> B1];
			int off = begin & M1, x = C1 - off, y = end - begin;
			int len = Math.min(x, y);
			init = act.call(va, off, len, init);
			if (init == -1) return;
			begin += len;
		}
	}

	/** 转成类似int[]类型的数组 */
	public T toArray() {
		return toArray(0, _length);
	}

	/** 转成类似int[]类型的数组
	 * @param begin 起始位置
	 * @param end 结束位置
	 * @return 数组
	 */
	public T toArray(int begin, int end) {
		int len = end - begin;
		T ret = newArray(len);
		toArray(begin, ret, 0, len);
		return ret;
	}

	/** 将指定数量的数组元素写入目标数组中
	 * @param srcPos 源位置
	 * @param dst 目标数组
	 * @param dstPos 目标位置
	 * @param count 写入个数
	 */
	public void toArray(int srcPos, final T dst, int dstPos, int count) {
		forEach(srcPos, srcPos + count, dstPos, (va, off, len, ret) -> {
			//noinspection SuspiciousSystemArraycopy
			System.arraycopy(va, off, dst, ret, len);
			return ret + len;
		});
	}

	/** 在末尾添加元素, 长度会自动+1 */
	public void add(T values) {
		int newLen = _length + Array.getLength(values);
		if (newLen > _capacity) increaseCapacity(newLen);
		forEach(_length, newLen, 0, (va, off, len, ret) -> {
			//noinspection SuspiciousSystemArraycopy
			System.arraycopy(values, ret, va, off, len);
			return ret + len;
		});
		_length = newLen;
	}

	/** 在指定位置设置多个元素, 长度不会发生变化
	 * @param index 索引位
	 * @param src 源数组
	 */
	public void set(int index, T src) {
		set(index, src, 0, Array.getLength(src));
	}
	
	/** 在指定位置设置多个元素, 如果超出当前长度, 将设置新的长度
	 * @param index 索引位
	 * @param src 源数组
	 * @param srcBegin 原数组起始位置
	 * @param srcEnd 原数组结束位置
	 */
	public void set(int index, T src, int srcBegin, int srcEnd) {
		int newLen = index + (srcEnd - srcBegin);
		if (newLen > _capacity) increaseCapacity(newLen);
		forEach(index, newLen, srcBegin, (va, off, len, ret) -> {
			//noinspection SuspiciousSystemArraycopy
			System.arraycopy(src, ret, va, off, len);
			return ret + len;
		});
		if (newLen > _length) _length = newLen;
	}

	/** 在指定位置插入数组
	 * @param index 起始位置
	 * @param src 源数组
	 */
	final public void insert(int index, T src) {
		if (src != null) insert(index, src, 0, Array.getLength(src));
	}

	/** 删除指定位置的元素, 后面的元素会前移, 长度会自动-1 */
	final public void delete(int index) {
		delete(index, index + 1);
	}

}
